﻿using FrameWork;
using System;
using System.Collections.Generic;
using UnityEngine;
using static FrameWork.ObjectPoolModule;

namespace GameFrameWork
{
    public class AssetModule : GameBaseModule
    {
        private ResourceModule _resourceModule;

        private LoadAssetCallBack _loadAssetCallBack;

        private LoadAssetCallBack _loadGoCallBack;

        public override void Init()
        {
            _resourceModule = ModuleGetter.ResourceModule;
            _loadAssetCallBack = new LoadAssetCallBack(LoadAssetOnSuccess, LoadAssetOnFail, LoadAssetOnUpdate);
            _loadGoCallBack = new LoadAssetCallBack(LoadGoOnSuc, LoadGoOnFail);
            _id2GoInstnaceDic = new Dictionary<int, GoInstance>();
            _loadingGoDic = new Dictionary<ObjectAsset<GameObject>, int>();
            _goPool = ModuleGetter.PoolModule.CreatePool<GoInstance>("GameObject Pool");
        }

        public override void ShutDown()
        {

        }

        public override void Update(float deltaTime, float realDeltaTime)
        {

        }

        #region LoadAsset
        public int LoadAsset<T>(string path, Action<bool, T> callBack) where T : UnityEngine.Object
        {
            var objectAsset = ObjectAsset<T>.Create(callBack);
            return _resourceModule.LoadAsset<T>(path, _loadAssetCallBack, objectAsset);
        }

        /// <summary>
        /// 加载成功回调
        /// </summary>
        /// <param name="uniqueKey">ui路径</param>
        /// <param name="result">ui实体</param>
        /// <param name="userData">传递的UI数据</param>
        private void LoadAssetOnSuccess(string uniqueKey, object result, object userData)
        {
            IObjectAsset objectAsset = userData as IObjectAsset;
            objectAsset.SetTarget(result);
            objectAsset.Invoke(true);
            objectAsset.Release();
        }

        /// <summary>
        /// 加载ui失败
        /// </summary>
        /// <param name="uniqueKey">UI路径</param>
        /// <param name="errorMessage">错误信息</param>
        private void LoadAssetOnFail(string uniqueKey, string errorMessage, object userData)
        {
            IObjectAsset objectAsset = userData as IObjectAsset;
            Debug.LogError($"加载资源{uniqueKey}失败");
            objectAsset.Invoke(false);
            objectAsset.Release();
        }

        /// <summary>
        /// 加载Update
        /// </summary>
        /// <param name="key"></param>
        /// <param name="loadBytes"></param>
        /// <param name="totalBytes"></param>
        /// <param name="percent"></param>
        private void LoadAssetOnUpdate(string key, float loadBytes, float totalBytes, float percent)
        {

        }

        /// <summary>
        /// 释放加载资源
        /// </summary>
        /// <param name="id"></param>
        public void ReleaseAsset(int id)
        {
            _resourceModule.ReleaseAsset(id);
        }

        #endregion LoadAsset

        #region LoadGameObject

        private ObjectPool<GoInstance> _goPool;

        /// <summary>
        /// 负责加载成功之后引用的查找
        /// </summary>
        private Dictionary<ObjectAsset<GameObject>, int> _loadingGoDic;

        /// <summary>
        /// 从id 到GoInstance 的引用
        /// </summary>

        private Dictionary<int, GoInstance> _id2GoInstnaceDic;

        public int LoadGo(string path, Action<bool, GameObject> cb)
        {
            GoInstance goInstance = _goPool.Spawn(path);
            if (goInstance != null)
            {
                cb?.Invoke(true, goInstance.Go);
                return goInstance.GoId;
            }

            ObjectAsset<GameObject> objectAsset = ObjectAsset<GameObject>.Create(cb);
            int loadId = _resourceModule.LoadAsset<GameObject>(path, _loadGoCallBack, objectAsset);
            _loadingGoDic.Add(objectAsset, loadId);
            return loadId;
        }

        private void LoadGoOnSuc(string uniqueKey, object result, object userData)
        {
            GameObject resultGo = result as GameObject;
            ObjectAsset<GameObject> goAsset = userData as ObjectAsset<GameObject>;
            goAsset.SetTarget(resultGo);

            GameObject cloneGo = GameObject.Instantiate(resultGo);
            int loadId = _loadingGoDic[goAsset];
            GoInstance goInstnace = GoInstance.CreateInstance(cloneGo, uniqueKey, loadId);
            _goPool.Register(goInstnace, true);
            goAsset.Invoke(true, resultGo);

            //移除正在加载的id
            _loadingGoDic.Remove(goAsset);
            _id2GoInstnaceDic.Add(loadId, goInstnace);
            goAsset.Release();
        }

        private void LoadGoOnFail(string uniqueKey, string errorMessage, object userData)
        {
            ObjectAsset<GameObject> goAsset = userData as ObjectAsset<GameObject>;
            if(_loadingGoDic.TryGetValue(goAsset,out int id))
            {
                _loadingGoDic.Remove(goAsset);
                goAsset.Invoke(false);
                goAsset.Release();
                return;
            }
            else
                throw new Exception("加载失败后无法查询到对应的缓存id");
        }

        public void ReleaseGo(int goId,bool isRecycle = true)
        {
            GoInstance goInstance = _id2GoInstnaceDic[goId];
            if (isRecycle)
            {
                _goPool.Unspawn(goInstance);
            }
            else
            {
                _goPool.ReleaseObject(goInstance);
                _resourceModule.ReleaseAsset(goId);
            }
        }
        #endregion
    }
}